﻿using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using YJKRevitCode.ElmentSearchUtility.LinkDocumentSuite;
using YJKRGeometry;
using ModelCheckUtility.ModelLayer;
using ModelCheckUtility.Properties;

namespace ModelCheckUtility.ControlLayer
{
	public static class BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass> where RoomClass : BaseRoomPacker where DoorClass : BaseDoorPacker where BoundarySegmentClass : BaseBoundarySegmentPacker where HostInRoomClass : BaseHostInRoomPacker
	{
		public static Document NowUseDocument
		{
			get
			{
				return BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.m_nowUseDocument;
			}
		}

		public static List<ResultBeanWithGeometryPacker> LstNowDoorValues
		{
			get
			{
				return BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.m_lstNowDoorValues;
			}
			private set
			{
				BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.m_lstNowDoorValues = value;
			}
		}

		public static bool IfUseRoomFinder
		{
			get
			{
				return BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.m_bIfUseRoomFinder;
			}
			private set
			{
				BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.m_bIfUseRoomFinder = value;
			}
		}

		public static void Reset()
		{
			BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.m_nowUseDocument = null;
			BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.LstNowDoorValues = new List<ResultBeanWithGeometryPacker>();
			BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.m_lstKVPfilteredElementIds = new List<KeyValuePair<int, int>>();
			BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.IfUseRoomFinder = false;
			ElementPackerManger.ReSet();
		}

		public static List<RoomClass> GetRoomPacker(Document useDocument, List<Level> useListLevel, List<Phase> useListPhase, List<BuiltInCategory> useHostedElementCategory, RoomClassFactory<RoomClass> useRoomFactory = null, DoorClassFactory<DoorClass> useDoorFactory = null, BoundarySegmentFactory<BoundarySegmentClass> useBoundarySegmentFactory = null, HostInRoomClassFactory<HostInRoomClass> useHostInRoomFactory = null)
		{
			BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.Reset();
			if (useDocument == null || useListLevel == null || useListPhase == null || useHostedElementCategory == null)
			{
				return new List<RoomClass>();
			}
			BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.m_roomFactory = useRoomFactory;
			BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.m_doorFactory = useDoorFactory;
			BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.m_boundarySemgentFactory = useBoundarySegmentFactory;
			BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.m_hostInRoomClassFactory = useHostInRoomFactory;
			BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.IfUseRoomFinder = true;
			BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.m_nowUseDocument = useDocument;
			BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.setNowAllDoors(useDocument);
			List<RoomClass> list = BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.findRoomPackers(useDocument, useListLevel, useListPhase);
			List<HostInRoomClass> list2 = BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.findHostedElementPackers(BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.NowUseDocument, useHostedElementCategory);
			for (int i = 0; i < list.Count; i++)
			{
				List<List<BoundarySegmentClass>> list3 = BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.addBoundarySegmentsToRoomPakcer(list[i]);
				for (int j = 0; j < list3.Count; j++)
				{
					for (int k = 0; k < list3[j].Count; k++)
					{
						BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.addDoorsToBoundarySegment(list3[j][k]);
					}
				}
			}
			BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.setRoomHost(ref list, ref list2);
			BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.setRoomLink(ref list);
			return list;
		}

		private static void setNowAllDoors(Document inpuDocument)
		{
			List<ResultBeanWithGeometryPacker> lstNowDoorValues = LinkDocumentUtility.QuickGetDocumetDoorBean(inpuDocument);
			BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.LstNowDoorValues = lstNowDoorValues;
		}

		private static void setRoomLink(ref List<RoomClass> inputValue)
		{
			if (inputValue == null)
			{
				return;
			}
			int count = inputValue.Count;
			bool flag = false;
			for (int i = 0; i < count; i++)
			{
				for (int j = 0; j < count; j++)
				{
					flag = false;
					if (j > i)
					{
						RoomClass roomClass = inputValue[i];
						RoomClass roomClass2 = inputValue[j];
						foreach (BaseDoorPacker baseDoorPacker in roomClass.LstBaseDoorPacker)
						{
							foreach (BaseDoorPacker baseDoorPacker2 in roomClass2.LstBaseDoorPacker)
							{
								if (baseDoorPacker.ThisElementPackerId == baseDoorPacker2.ThisElementPackerId)
								{
									flag = true;
									break;
								}
							}
						}
						if (flag)
						{
							roomClass.AddNearRoom(roomClass2);
							roomClass2.AddNearRoom(roomClass);
						}
					}
				}
			}
		}

		private static void setRoomHost(ref List<RoomClass> inputRooms, ref List<HostInRoomClass> inputHostElements)
		{
			XYZ xyz = null;
			for (int i = 0; i < inputRooms.Count; i++)
			{
				RoomClass roomClass = inputRooms[i];
				for (int j = 0; j < inputHostElements.Count; j++)
				{
					HostInRoomClass hostInRoomClass = inputHostElements[j];
					if (Utility.IfHostElementPackerCanHostInRoomPacker(roomClass, hostInRoomClass, out xyz))
					{
						roomClass.AddHostedElement(hostInRoomClass, xyz);
						hostInRoomClass.AddHostRoom(roomClass, xyz);
					}
				}
			}
		}

		private static List<HostInRoomClass> findHostedElementPackers(Document useDocument, List<BuiltInCategory> lstCategorys)
		{
			List<HostInRoomClass> list = new List<HostInRoomClass>();
			List<KeyValuePair<Element, RevitLinkInstance>> list2 = new List<KeyValuePair<Element, RevitLinkInstance>>();
			foreach (BuiltInCategory inputCategory in lstCategorys)
			{
				list2 = Utility.GetAllElement<Element>(useDocument, inputCategory, null);
				foreach (KeyValuePair<Element, RevitLinkInstance> keyValuePair in list2)
				{
					if (!BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.ifElementFiltered(keyValuePair.Key, keyValuePair.Value))
					{
						HostInRoomClass hostInRoomClass;
						if (BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.m_hostInRoomClassFactory == null)
						{
							Type typeFromHandle = typeof(HostInRoomClass);
							object[] array = new object[3];
							array[0] = keyValuePair.Key;
							array[1] = keyValuePair.Value;
							hostInRoomClass = (HostInRoomClass)((object)Activator.CreateInstance(typeFromHandle, array));
						}
						else
						{
							hostInRoomClass = BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.m_hostInRoomClassFactory(keyValuePair.Key, keyValuePair.Value, null);
						}
						hostInRoomClass = (ElementPackerManger.GetBaseElementPacker(hostInRoomClass.ThisElementPackerId) as HostInRoomClass);
						if (hostInRoomClass != null)
						{
							list.Add(hostInRoomClass);
						}
					}
				}
			}
			return list;
		}

		private static List<RoomClass> findRoomPackers(Document useDocument, List<Level> useLstLevel, List<Phase> useListPhase)
		{
			List<RoomClass> list = new List<RoomClass>();
			foreach (Level useLevel in useLstLevel)
			{
				foreach (Phase usePhase in useListPhase)
				{
					list.AddRange(BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.findRoomPackers(useDocument, useLevel, usePhase));
				}
			}
			return list;
		}

		private static List<RoomClass> findRoomPackers(Document useDocument, Level useLevel, Phase usePhase)
		{
			List<RoomClass> list = new List<RoomClass>();
			new List<Room>();
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(useDocument);
			foreach (Element element in filteredElementCollector.OfCategory(BuiltInCategory.OST_Rooms).WhereElementIsNotElementType().ToElements())
			{
				Room room = (Room)element;
				if (room != null && !Geometry.Lessthan_Or_Equal(room.Area, 0.0, 1E-06) && !BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.ifElementFiltered(room, null))
				{
					Parameter parameter = room.get_Parameter(BuiltInParameter.ROOM_PHASE_ID);
					if (parameter != null && room.LevelId.IntegerValue == useLevel.Id.IntegerValue && parameter.AsElementId().IntegerValue == usePhase.Id.IntegerValue)
					{
						BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.addRoomClassInList(list, room, null);
					}
				}
			}
			return list;
		}

		private static List<List<BoundarySegmentClass>> addBoundarySegmentsToRoomPakcer(RoomClass input)
		{
			List<List<BoundarySegmentClass>> list = new List<List<BoundarySegmentClass>>();
			List<List<BaseBoundarySegmentPacker>> list2 = new List<List<BaseBoundarySegmentPacker>>();
			Document document = input.ThisRoom.Document;
			Room thisRoom = input.ThisRoom;
			int num = 0;
			int num2 = int.Parse(Resources.Str_ValueOfNoneElementId);
			foreach (IList<BoundarySegment> list3 in thisRoom.GetBoundarySegments(new SpatialElementBoundaryOptions()))
			{
				list.Add(new List<BoundarySegmentClass>());
				list2.Add(new List<BaseBoundarySegmentPacker>());
				foreach (BoundarySegment boundarySegment in list3)
				{
					if (!(null == boundarySegment.GetCurve()))
					{
						Element element;
						RevitLinkInstance revitLinkInstance;
						if (boundarySegment.LinkElementId.IntegerValue == num2)
						{
							element = document.GetElement(boundarySegment.ElementId);
							revitLinkInstance = null;
						}
						else
						{
							revitLinkInstance = (document.GetElement(boundarySegment.ElementId) as RevitLinkInstance);
							Document linkDocument = revitLinkInstance.GetLinkDocument();
							element = linkDocument.GetElement(boundarySegment.LinkElementId);
						}
						if (!BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.ifElementFiltered(element, revitLinkInstance))
						{
							BoundarySegmentClass boundarySegmentClass;
							if (BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.m_boundarySemgentFactory == null)
							{
								boundarySegmentClass = (BoundarySegmentClass)((object)Activator.CreateInstance(typeof(BoundarySegmentClass), new object[]
								{
									boundarySegment,
									element,
									revitLinkInstance
								}));
							}
							else
							{
								boundarySegmentClass = BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.m_boundarySemgentFactory(boundarySegment, element, revitLinkInstance);
							}
							boundarySegmentClass.ThisRoomPacker = input;
							list[num].Add(boundarySegmentClass);
							list2[num].Add(boundarySegmentClass);
						}
					}
				}
				num++;
			}
			input.LstLstBoundarySegmentPacker = list2;
			return list;
		}

		private static List<DoorClass> addDoorsToBoundarySegment(BoundarySegmentClass input)
		{
			List<DoorClass> list = new List<DoorClass>();
			Curve boundaryCurve = input.BoundaryCurve;
			int num = -1;
			DoorClass tempAddedValue = default(DoorClass);
			if (input.ThisElement != null && input.ThisRoomPacker != null)
			{
				double nowDownZ = input.ThisRoomPacker.NowDownZ;
				double nowTopZ = input.ThisRoomPacker.NowTopZ;
				if (input.ThisElement is Wall)
				{
					if (input.IfLinkedFileElement)
					{
						Document document = input.UseRevitLinkInstance.Document;
						input.UseRevitLinkInstance.GetLinkDocument();
						num = input.UseRevitLinkInstance.Id.IntegerValue;
					}
					else
					{
						Document document2 = input.ThisElement.Document;
					}
					foreach (ResultBeanWithGeometryPacker resultBeanWithGeometryPacker in BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.LstNowDoorValues)
					{
						FamilyInstance familyInstance = null;
						if (resultBeanWithGeometryPacker.UseElement is FamilyInstance)
						{
							familyInstance = (resultBeanWithGeometryPacker.UseElement as FamilyInstance);
						}
						if (familyInstance != null && !BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.ifElementFiltered(familyInstance, resultBeanWithGeometryPacker.UseLinkeInstance) && familyInstance.Host.Id.IntegerValue == input.ThisElement.Id.IntegerValue && resultBeanWithGeometryPacker.LinkeInstanceId == num)
						{
							if (resultBeanWithGeometryPacker.UseElementGeometryPacker.MinZ >= nowDownZ - 0.1 && resultBeanWithGeometryPacker.UseElementGeometryPacker.MaxZ <= nowTopZ + 0.1)
							{
								tempAddedValue = BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.TrayAddedDoor(input, list, boundaryCurve, tempAddedValue, resultBeanWithGeometryPacker);
							}
							else if (resultBeanWithGeometryPacker.UseElementGeometryPacker.MaxZ >= nowDownZ - 0.1 && resultBeanWithGeometryPacker.UseElementGeometryPacker.MinZ < nowDownZ - 0.1)
							{
								tempAddedValue = BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.TrayAddedDoor(input, list, boundaryCurve, tempAddedValue, resultBeanWithGeometryPacker);
							}
						}
					}
				}
			}
			return list;
		}

		private static DoorClass TrayAddedDoor(BoundarySegmentClass input, List<DoorClass> retrunValues, Curve useCurve, DoorClass tempAddedValue, ResultBeanWithGeometryPacker inputBean)
		{
			if (Utility.IfGeometryPackerCanProjectToCurve(useCurve, inputBean.UseElementGeometryPacker))
			{
				if (BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.m_doorFactory == null)
				{
					tempAddedValue = (DoorClass)((object)Activator.CreateInstance(typeof(DoorClass), new object[]
					{
						inputBean.UseElement,
						inputBean.UseLinkeInstance,
						inputBean.UseElementGeometryPacker
					}));
				}
				else
				{
					tempAddedValue = BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.m_doorFactory(inputBean.UseElement as FamilyInstance, inputBean.UseLinkeInstance, inputBean.UseElementGeometryPacker);
				}
				tempAddedValue = (ElementPackerManger.GetBaseElementPacker(tempAddedValue.ThisElementPackerId) as DoorClass);
				if (tempAddedValue == null)
				{
					throw new ModelCheckUtilityException(Resources.Exception_GetPackerError);
				}
				retrunValues.Add(tempAddedValue);
				input.AddDoor(tempAddedValue);
				input.ThisRoomPacker.AddDoor(tempAddedValue);
				tempAddedValue.AddConctRoom(input.ThisRoomPacker);
			}
			return tempAddedValue;
		}

		private static RoomClass addRoomClassInList(List<RoomClass> returnValues, Room tempAddedRoom, PlanCircuit tempPlanCircuit = null)
		{
			RoomClass roomClass;
			if (BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.m_roomFactory == null)
			{
				Type typeFromHandle = typeof(RoomClass);
				object[] array = new object[2];
				array[0] = tempAddedRoom;
				roomClass = (RoomClass)((object)Activator.CreateInstance(typeFromHandle, array));
			}
			else
			{
				roomClass = BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.m_roomFactory(tempAddedRoom, null);
			}
			roomClass = (ElementPackerManger.GetBaseElementPacker(roomClass.ThisElementPackerId) as RoomClass);
			if (roomClass != null)
			{
				returnValues.Add(roomClass);
			}
			return roomClass;
		}

		private static bool ifElementFiltered(Element useElement = null, RevitLinkInstance useLinkInstance = null)
		{
			if (BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.m_lstKVPfilteredElementIds == null || BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.m_lstKVPfilteredElementIds.Count == 0)
			{
				return false;
			}
			int num = -1;
			int num2 = -1;
			if (useLinkInstance != null)
			{
				num = useLinkInstance.Id.IntegerValue;
			}
			if (useElement != null)
			{
				num2 = useElement.Id.IntegerValue;
			}
			foreach (KeyValuePair<int, int> keyValuePair in BaseRoomFinder<RoomClass, DoorClass, BoundarySegmentClass, HostInRoomClass>.m_lstKVPfilteredElementIds)
			{
				if (num2 == keyValuePair.Value && num == keyValuePair.Key)
				{
					return true;
				}
			}
			return false;
		}

		private static RoomClassFactory<RoomClass> m_roomFactory = null;

		private static DoorClassFactory<DoorClass> m_doorFactory = null;

		private static BoundarySegmentFactory<BoundarySegmentClass> m_boundarySemgentFactory = null;

		private static HostInRoomClassFactory<HostInRoomClass> m_hostInRoomClassFactory = null;

		private static List<KeyValuePair<int, int>> m_lstKVPfilteredElementIds = new List<KeyValuePair<int, int>>();

		private static Document m_nowUseDocument;

		private static List<ResultBeanWithGeometryPacker> m_lstNowDoorValues;

		private static bool m_bIfUseRoomFinder = false;
	}
}
